package com.ayz.gateway.core.rpc.config;

import cn.hutool.log.Log;

import com.ayz.gateway.core.context.config.Configuration;
import com.ayz.gateway.core.rpc.GenericReferenceProxyFactory;
import com.ayz.gateway.core.rpc.GenericReferenceRegistry;
import com.ayz.gateway.core.rpc.IGatewayApi;
import com.ayz.gateway.core.rpc.MappedMethod;
import com.ayz.gateway.core.rpc.dubbo.DubboGenericReferenceRegistry;
import com.ayz.gateway.core.rpc.exception.MappedMethodNotFoundException;
import lombok.Getter;
import lombok.Setter;
import org.apache.dubbo.config.ApplicationConfig;
import org.apache.dubbo.config.ReferenceConfig;
import org.apache.dubbo.config.RegistryConfig;
import org.apache.dubbo.config.bootstrap.DubboBootstrap;
import org.apache.dubbo.rpc.service.GenericService;

import java.util.concurrent.ConcurrentHashMap;

/**
 * @ClassName Configuration
 * @Description TODO: 配置项数据用于 贯穿网关的整个生命周期 存储代理对象和配置信息
 * @Author 快乐的星球
 * @Date 2023/5/6 20:47
 * @Version 1.0
 **/
@Getter
@Setter
public class DubboConfiguration implements Configuration {

    private final Log LOG=Log.get(DubboConfiguration.class);
    /**
     * Dubbo服务的启动器
     * 整个网关服务上下文唯一单例
     */
    private DubboBootstrap dubboBootstrap;

    /**
     * 注册中心的配置与服务名称的映射
     * 默认是Dubbo的应用级注册
     */
    private final ConcurrentHashMap<String, RegistryConfig> registryConfigMap=
            new ConcurrentHashMap<>();
    /**
     * 服务引用配置和接口的映射关系
     */
    private final ConcurrentHashMap<String, ReferenceConfig<GenericService>> referenceConfigMap=
            new ConcurrentHashMap<>(1024);

    /**
     * 泛化引用注册器
     */
    private final GenericReferenceRegistry genericReferenceRegistry=new DubboGenericReferenceRegistry(this);
    /**
     * 存储http uri资源和RPC资源的映射关系
     */
    private final ConcurrentHashMap<String, MappedMethod> uriResourceMappingRpcMethod=
            new ConcurrentHashMap<>(1024);

    public DubboConfiguration(String applicationName,String registryAddress) {
        this.dubboBootstrap=DubboBootstrap.getInstance();
        ApplicationConfig applicationConfig=new ApplicationConfig();
        applicationConfig.setName(applicationName);
        /**
         * 网关服务应该只作为服务消费者存在，作为集群中所有服务的服务消费者
         */
        applicationConfig.setRegisterConsumer(true);
//        RegistryConfig registryConfig=new RegistryConfig();
//        registryConfig.setAddress(registryAddress);
//        applicationConfig.setRegistry(registryConfig);
        this.dubboBootstrap.application(applicationConfig);
        this.dubboBootstrap.start();
    }
    public RegistryConfig getRegistryConfig(String applicationName){
        return registryConfigMap.get(applicationName);
    }

    public void addRegistryConfig(String applicationName,RegistryConfig registryConfig){
        registryConfigMap.put(applicationName,registryConfig);
    }

    public ReferenceConfig<GenericService> getReferenceConfig(String interfaceName){
        return this.referenceConfigMap.get(interfaceName);
    }

    public void addReferenceConfig(String interfaceName,ReferenceConfig<GenericService> referenceConfig){
        this.referenceConfigMap.put(interfaceName,referenceConfig);
    }

    /**
     * 注册生成泛化调用代理的的工厂
     * @param applicationName 应用程序的名称
     * @param interfaceName   接口的名称
     * @param methodName   rpc资源方法的名称
     */
    public void registryGenericReference(String applicationName, String interfaceName, String methodName){
        LOG.info("GenericReference注册;applicationName:{},interfaceName:{},rpcMethodName:{}",applicationName,interfaceName,methodName);
        this.genericReferenceRegistry.registryGenericReference(applicationName,interfaceName,methodName);
    }

    /**
     * 根据RPC资源名称获取到具体的RPC资源泛化调用代理对象
     * @param rpcResource rpc资源唯一名称
     * @return 代理对象
     */
    public IGatewayApi getGenericReference(String rpcResource){
        GenericReferenceRegistry genericReferenceRegistry = this.genericReferenceRegistry;
        //根据 RPC资源唯一名称获取到对应的GenericReferenceProxyFactory对象
        GenericReferenceProxyFactory genericReference = genericReferenceRegistry.getGenericReference(rpcResource);
        return genericReference.newInstance();
    }

    public void registerURIMapped(String httpUri,MappedMethod mappedMethod){
        this.uriResourceMappingRpcMethod.put(httpUri,mappedMethod);
    }

    public MappedMethod getMappedMethod(String httpUri){
        MappedMethod mappedMethod = this.uriResourceMappingRpcMethod.get(httpUri);
        if(mappedMethod==null){
            LOG.error("指定的uri:{}没有绑定RPC资源",httpUri);
            throw new MappedMethodNotFoundException("指定的HttpUri没有绑定RPC资源{"+httpUri+"}");
        }
        return mappedMethod;
    }


    public ConcurrentHashMap<String, RegistryConfig> getRegistryConfigMap() {
        return registryConfigMap;
    }

    public ConcurrentHashMap<String, ReferenceConfig<GenericService>> getReferenceConfigMap() {
        return referenceConfigMap;
    }

    public GenericReferenceRegistry getGenericReferenceRegistry() {
        return genericReferenceRegistry;
    }

    public ConcurrentHashMap<String, MappedMethod> getUriResourceMappingRpcMethod() {
        return uriResourceMappingRpcMethod;
    }
}
